package com.lazy.tcp;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;

import com.lazy.tcp.TelnetServer.IListener;




public class TelnetServerHandler extends SimpleChannelUpstreamHandler {
	
	private static Logger logger = Logger.getLogger("TelnetServer");
	static final ChannelGroup channels = new DefaultChannelGroup();
	   /** store the data that received */
    private final BlockingQueue<String> answerQueue = new LinkedBlockingQueue<String>();
    private IListener receivedListener = null;
    
    private static AtomicInteger totalReceived = new AtomicInteger();
    
    public static int getReceivePacketCount() {
        return totalReceived.get();
    }

    /**
     * @deprecated 代码改为异步接受数据，暂时该函数无效
     * @return
     */
    public String getAnswer() {
        String buf = null;
        try {
            buf = answerQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error("Error when getAnswer() with " + e.getMessage());
        }
        return buf;
    }
	   
    public ChannelGroup getChannels() {
        return channels;
    }
    

    public void setReceivedListener(IListener listener) {
        receivedListener = listener;
    }

	@Override
	public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
		if (e instanceof ChannelStateEvent) {
			logger.info(e.toString());
		}
		super.handleUpstream(ctx, e);
	}
	
	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		logger.info("channel connected ...");
//		logger.info("local:" + e.getChannel().getLocalAddress().toString());
//		logger.info("remote:" + e.getChannel().getRemoteAddress().toString());
		e.getFuture().addListener(new ConnectedListener());
    }

    @Override
    public void channelDisconnected(
            ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		logger.info("channel disconnected ...");
        // Unregister the channel from the global channel list
        // so the channel does not receive messages anymore.
        channels.remove(e.getChannel());
    }

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {		
        // Cast to a String first.
        // We know it is a String because we put some codec in TelnetPipelineFactory.
        String request = (String) e.getMessage();
        totalReceived.addAndGet(1);
        // Generate and write a response.
        String response = null;
        logger.info("server received:[" + totalReceived.get() + "]" + request);
        boolean close = false;
        if ("bye".equals(request.toLowerCase())) {
            response = "bye\r\n";
            close = true;
        } else {
            response = request;
        }

        // We do not need to write a ChannelBuffer here.
        // We know the encoder inserted at TelnetPipelineFactory will do the conversion.
        if (response != null) {
            ChannelFuture future = e.getChannel().write(response);
    
            // Close the connection after sending 'Have a good day!'
            // if the client has sent 'bye'.
            if (close) {
                future.addListener(ChannelFutureListener.CLOSE);
            }
        }
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
		logger.warn("Unexpected exception from downstream." + e.getCause());
		e.getChannel().close();
	}
	
	private static final class ConnectedListener implements ChannelFutureListener {
		
		public void operationComplete(ChannelFuture future) throws Exception {
			if (future.isSuccess()) {
				// Register the channel to the global channel list
				// so the channel received the messages from others.
				channels.add(future.getChannel());
			} else {
				future.getChannel().close();
			}
		}
	}
}
